import type { Services } from '../electron/main/service.ts'

type IfPromise<T> = T extends Promise<infer R> ? Promise<R> : Promise<T>

export type Promisify<T> = T extends (...args: infer K) => infer R
    ? K extends [...infer Q, event: Electron.IpcMainInvokeEvent]
        ? (...args: Q) => IfPromise<R>
        : (...args: K) => IfPromise<R>
    : T extends object
        ? { [K in keyof T]: Promisify<T[K]> }
        : T

const rpc = (paths: string[], args: any[]) => {
    const global = window as any
    if (!global.ipcRenderer) {
        throw new Error('jsBridge is not ready')
    }
    return global.ipcRenderer.invoke('jsBridge', paths, ...args)
}

const methodProxy = (paths: string[]) => {
    return new Proxy(new Function(), {
        get: (_target, prop: string) => {
            return methodProxy([...paths, prop])
        },
        apply: (_target, _thisArg, args) => {
            return rpc(paths, args)
        }
    })
}

const jsBridge = new Proxy(
    {},
    {
        get: (_target, prop: string) => {
            return methodProxy([prop])
        }
    }
) as Promisify<Services>

export default jsBridge
